package cn.eeepay.framework.service.unTransactionalImpl;

import cn.eeepay.boss.thread.UserCouponRunnable;
import cn.eeepay.framework.dao.SysDictDao;
import cn.eeepay.framework.dao.TransInfoDao;
import cn.eeepay.framework.dao.UserCouponDao;
import cn.eeepay.framework.model.MerchantInfo;
import cn.eeepay.framework.model.SysDict;
import cn.eeepay.framework.model.UserCoupon;
import cn.eeepay.framework.model.ZqMerchantInfo;
import cn.eeepay.framework.service.*;
import cn.eeepay.framework.service.impl.SensorsService;
import cn.eeepay.framework.util.ClientInterface;
import cn.eeepay.framework.util.DateUtil;
import cn.eeepay.framework.util.StringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;


/**
 * @author tans
 * @date 2019/4/12 10:33
 */
@Service("taskService")
public class TaskServiceImpl implements TaskService {

    @Resource
    private SysDictService sysDictService;
    @Resource
    private TransInfoService transInfoService;
    @Resource
    private MerchantInfoService merchantInfoService;
    @Resource
    private ZqMerchantInfoService zqMerchantInfoService;
    @Resource
    private RedisService redisService;
    @Resource
    private UpdateCheGuanHomeOrderService updateCheGuanHomeOrderService;

    @Resource
    private TransInfoDao transInfoDao;
    @Resource
    private SysDictDao sysDictDao;
    @Resource
    private UserCouponDao userCouponDao;
    @Resource
    private SensorsService sensorsService;
    // 商户业务产品
    @Resource
    private MerchantBusinessProductService merchantBusinessProductService;

    private static final Logger log = LoggerFactory.getLogger(TaskServiceImpl.class);

    @Override
    public void createMerAcc() {
        List<MerchantInfo> merList = merchantInfoService.selectByMerAccount();
        log.info("===========需要开户数量==="+merList.size());
        if(merList!=null && merList.size()>0){
            for (MerchantInfo merchantInfo : merList){
                String merchantNo = merchantInfo.getMerchantNo();
                String acc= ClientInterface.createMerchantAccount(merchantNo);
                log.info("商户批量开户,商户号:{},返回结果:{}", merchantNo,acc);
                JSONObject returnJson = JSONObject.parseObject(acc);
                if(returnJson.getBooleanValue("status") || "外部账号已经存在".equals(returnJson.getString("msg"))){
                    int i = merchantInfoService.updateMerAcoount(merchantNo);
                    if(i>0){
                        log.info("开立商户账户成功");
                    }else{
                        log.info( "开立商户账户失败");
                    }
                }else{
                    log.info( "开立商户账户失败");
                }
            }
        }
    }

    @Override
    public int updateSettleStatus() {
        int res1 =0;//T0的单转T1结算
//        int res2 =0;//提现失败的单转T1
        List<String> orderList = new ArrayList<>();
        // 如果不是节假日执行
        if (transInfoDao.getHolidayFlag(new SimpleDateFormat("yyyy-MM-dd").format(new Date())) == null) {
            // 获取更新参数
            String channels = sysDictService.getValues("NO_UPDATE_SETTLE_STATUS");
            String maxdate = sysDictDao.getValueByKey("NO_UPDATE_SETTLE_STATUS_DATA");
            String currentDate = DateUtil.getCurrentDate();
            maxdate = DateUtil.getBeforeDate(new Date(), Integer.parseInt(maxdate));
            log.info("更改交易结算状态，订单时间{}~{}",maxdate, currentDate);
            //先找出订单号，再更新
            orderList = transInfoDao.selectT0SettleOrderList(channels,maxdate,currentDate);
            List<String> t1OrderNoList = transInfoDao.selectT1SettleOrderList(channels,maxdate,currentDate);
            orderList.addAll(t1OrderNoList);
            // T0的单转T1结算
//            res1=transInfoDao.updateT0SettleStatus(channels,maxdate,currentDate);
            // 提现失败的单转T1
//            res2=transInfoDao.updateT1SettleStatus(channels,maxdate,currentDate);
        }else{
            String transchannels = sysDictService.getValues("HOLIDAYS_UPDATE_SETTLE_STATUS");
            if(transchannels.length() > 0){
                String channels = sysDictService.getValues("NO_UPDATE_SETTLE_STATUS");
                String maxdate = sysDictDao.getValueByKey("NO_UPDATE_SETTLE_STATUS_DATA");
                String currentDate = DateUtil.getCurrentDate();
                maxdate = DateUtil.getBeforeDate(new Date(), Integer.parseInt(maxdate));
                log.info("更改交易结算状态，订单时间{}~{}",maxdate, currentDate);
                //先查出订单号，再更新
                orderList = transInfoDao.selectT0HolidaySettleOrderList(channels,maxdate,transchannels,currentDate);
                List<String> t1OrderNoList = transInfoDao.selectT1HolidaySettleOrderList(channels,maxdate,transchannels,currentDate);
                orderList.addAll(t1OrderNoList);
                // T0的单转T1结算
//                res1=transInfoDao.updateT0SettleStatus2(channels,maxdate,transchannels,currentDate);
//                // 提现失败的单转T1
//                res2=transInfoDao.updateT1SettleStatus2(channels,maxdate,transchannels,currentDate);
            }
        }
        res1 = updateSettleBatch(orderList);
        log.info("更新交易的结算状态,条数:{}", res1);
        return res1;
    }

    private int updateSettleBatch(List<String> t0OrderNoList) {
        int num = 0;
        if(t0OrderNoList == null || t0OrderNoList.isEmpty()){
            return num;
        }
        List<String> list = new ArrayList<>();
        for(int i = 0; i < t0OrderNoList.size(); i++){
            if(i == 0 || i % 300 > 0){
                list.add(t0OrderNoList.get(i));
            }
            if(list.size() % 300 == 0){
                num += transInfoDao.updateSettle(list);
                list.clear();
            }
        }
        if(list != null && list.size() > 0){
            num += transInfoDao.updateSettle(list);
        }
        return num;
    }

    @Override
    public void updateCouponStatus() {
        log.info("updateCouponStatus.start,定时更新优惠劵状态开始");
        userCouponDao.updateCouponStatus();
        final Map couponCodeMap=sysDictService.selectMapByKey("COUPON_CODE");
        //查询过期优惠券总数
        int countNum = userCouponDao.queryCountExpCoupons();
        if(countNum <= 0) {
            return;
        }
        //如果需要处理的数据在100条以内，就单线程处理
        if(countNum <= 100) {
            dealExpCoupons(couponCodeMap);
        } else {
            //否则就开多线程处理
            dealExpCouponsBatchThead(couponCodeMap, countNum);
        }
        log.info("updateCouponStatus.end,定时更新优惠劵状态结束");
        return;

        //获取过期充值返数据写入核销表
//        List<UserCoupon> expCoupons = userCouponDao.queryExpCoupons();
//        List<UserCoupon> insertCoupons=new ArrayList<UserCoupon>();
//        if(expCoupons != null && expCoupons.size() > 0){
//            String order = DateUtil.getMessageTextTime().toString();
//
//            for(int i = 0; i < expCoupons.size(); i ++){
//
//                if(expCoupons.get(i).getCouponCode().equals("3")||expCoupons.get(i).getCouponCode().equals("6")){
//                    UserCoupon userCoupon=expCoupons.get(i);
//                    userCoupon.setToken("EXP"+order+i);
//                    userCoupon.setCouponStatus("0");
//                    userCoupon.setCancelVerificationType("3");
//                    insertCoupons.add(userCoupon);
//                }
//
//                final UserCoupon userCoupon = expCoupons.get(i);
//
//                ThreadFactory.getThread().execute(new Runnable() {
//                    @Override
//                    public void run() {
//                        log.info("-------------创建线程异步调用神策接口------------------");
//                        sensorsService.invalidCoupon(userCoupon, couponCodeMap);
//                    }
//                });
//
//            }
//            if(insertCoupons != null && insertCoupons.size() > 0){
//                userCouponDao.batchInsertexpCoupon(insertCoupons);
//            }
//        }
        //获取过期的充值返商户、金额、提示消息
//        List<Map<String, Object>> expCoupon = userCouponDao.queryExpCoupon();
//        if(expCoupons != null && expCoupon.size() > 0){
//            for(int i = 0; i < expCoupon.size(); i ++){
//                try {
//                    String point = String.valueOf(new BigDecimal(expCoupon.get(i).get("balance").toString()).multiply(new BigDecimal("100")).intValueExact());
//                    String msm = expCoupon.get(i).get("activity_notice").toString()+"过期"+point+"积分";
//                    List<NameValuePair> list=new ArrayList<NameValuePair>();
//                    list.add(new BasicNameValuePair("title", "充值券过期提醒"));//标题
//                    list.add(new BasicNameValuePair("notice", msm));//消息内容
//                    list.add(new BasicNameValuePair("mer_no", expCoupon.get(i).get("merchant_no").toString()));//商户号
//                    //如果不.returnContent()，request不会释放，顶多100个，超过100个将不会发出请求
//                    Content content = Request.Post(Constants.EXPCOUPON_MSM_URL).body(new UrlEncodedFormEntity(list, "utf-8")).execute().returnContent();
//                    if(content != null){
//                        log.info("returnMsg:{}", content.asString());
//                    }
//                    //successCount++;
//                } catch (Exception e) {
//                    log.error("充值卷过期提醒异常:{}",expCoupon.get(i),e);
//                    break;
//                }
//            }
//        }
    }

    /**
     * 多线程处理过期优惠券
     * @param couponCodeMap
     * @param countNum 需要处理的总数据量
     */
    private void dealExpCouponsBatchThead(Map couponCodeMap, int countNum) {
        int threadNum = 10;//默认10个线程，数据字典可配置为1~30
        //查询处理的异步线程数
        String threadNumStr = sysDictService.getValueByKey("USER_COUPON_THREAD_NUM");
        if(StringUtil.isNotBlank(threadNumStr)) {
            int itemNum = Integer.parseInt(threadNumStr);
            if(itemNum >= 1 && itemNum <= 30) {
                threadNum = itemNum;
            }
        }
        //如果线程数多于需要处理的总数量，则单线程处理
        if(threadNum > countNum) {
            dealExpCoupons(couponCodeMap);
            return ;
        }
        CountDownLatch countDownLatch = new CountDownLatch(threadNum);
        List<Thread> threadList = new ArrayList<>();
        int pageSize = countNum / threadNum;
        for(int pageNo = 0; pageNo < threadNum; pageNo++) {
            //查询每页数据的最小ID和最大ID
            Long minId = userCouponDao.queryExpCouponsId(pageNo * pageSize);
            Long maxId;
            //如果是最后一页
            if(pageNo == threadNum - 1) {
                maxId = userCouponDao.queryExpCouponsLastId();
            } else {
                maxId = userCouponDao.queryExpCouponsId((pageNo + 1) * pageSize - 1);
            }
            threadList.add(new Thread(new UserCouponRunnable(minId, maxId, countDownLatch, userCouponDao, sensorsService, couponCodeMap)));
        }
        for (Thread thread: threadList) {
            thread.start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            log.error("定时更新优惠劵状态异常，", e);
        }
    }

    /**
     * 处理过期优惠券
     * @param couponCodeMap
     */
    public void dealExpCoupons(Map couponCodeMap){
//        获取过期充值返数据写入核销表
        List<UserCoupon> expCoupons = userCouponDao.queryExpCoupons();
        List<UserCoupon> insertCoupons=new ArrayList<UserCoupon>();
        if(expCoupons != null && expCoupons.size() > 0){
            String order = DateUtil.getMessageTextTime().toString();
            for(int i = 0; i < expCoupons.size(); i ++){
                if(expCoupons.get(i).getCouponCode().equals("3")||expCoupons.get(i).getCouponCode().equals("6")){
                    UserCoupon userCoupon=expCoupons.get(i);
                    userCoupon.setToken("EXP"+order+i);
                    userCoupon.setCouponStatus("0");
                    userCoupon.setCancelVerificationType("3");
                    insertCoupons.add(userCoupon);
                }
                try {
                    sensorsService.invalidCoupon(expCoupons.get(i), couponCodeMap);
                } catch (Exception e) {
                    log.error("调用神策异常", e);
                }
            }
            if(insertCoupons != null && insertCoupons.size() > 0){
                userCouponDao.batchInsertexpCoupon(insertCoupons);
            }
        }
    }

    @Override
    public void ysMerAdd() {
        log.info("=============YS同步商户定时任务开始=========");
        String paramStr;
        String merchantNo = null;
        SysDict sysDict = sysDictService.getByKey("ZFZQ_ACCESS_URL");
        String accessUrl = sysDict.getSysValue() + "zfMerchant/zfMerUpdate";
        SysDict type = sysDictService.getByKey("YS_MERADD_TIME");
        List<ZqMerchantInfo> zqMerList = zqMerchantInfoService.selectYsSyncMer(String.valueOf(type.getSysValue()));
        if(zqMerList != null && zqMerList.size()>0){
            for (ZqMerchantInfo zqMerInfo : zqMerList) {
                try{
                    merchantNo = zqMerInfo.getMerchantNo();
                    String bpId = zqMerInfo.getBpId().toString();
                    Map<String, Object> marMap = new HashMap<String, Object>();
                    List<String> channelList = new ArrayList<>();
                    channelList.add("YS_ZQ");
                    marMap.put("merchantNo", merchantNo);
                    marMap.put("bpId", bpId);
                    marMap.put("operator", merchantNo);
                    marMap.put("changeSettleCard", "0");
                    marMap.put("channelCode", channelList);
                    paramStr = JSON.toJSONString(marMap);
                    new ClientInterface(accessUrl, null).postRequestBody(paramStr);
                }catch(Exception e){
                    log.error("YS商户定时任务同步异常,商户号:{}",new Object[]{merchantNo});
                }

            }
        }
    }

    @Override
    public void updateCarManagerStatus() {
        try {
            log.info("修改车管家订单结算状态后台线程 启动:----------->");
            int count=updateCheGuanHomeOrderService.updateCheGuanHomeOrder();
            if(count>0) {
                log.info("修改车管家订单结算状态后台线程:本次共更新了 " + count + " 条记录!");
            }
            log.info("修改车管家订单结算状态后台线程 结束!");
        } catch (Exception e) {
            e.printStackTrace();
            log.info("修改车管家订单结算状态后台线程 异常: "+e.getMessage());
        }
    }
}
